package nicg.st.service.ahp;

import nicg.st.entity.Node;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * @author GeChen
 * @Description
 * @date 2019/11/3 23:03
 */
public class AHP {
    private int NSolution = 0;              // 方案层方案的数量

    /**
     * @return 属性的绝对权重
     * @Author WH
     * @Description 多个方案对比主函数
     * @Date 2019/3/31 16:07
     * @Param 层次分析法对应的树
     **/
    public double[] ahp(Node ahpTree) {
        return ahp(ahpTree, 0.1);
    }

    public double[] ahp(Node ahpTree, double CR) {
        // 计算各节点最大特征值及其特征向量、层次单排序一致性检验及调整
        preOrdor(ahpTree, CR);
        // 计算属性的绝对权重向量
        double[] w = new double[NSolution];
        calAbVector(ahpTree, 1, w);
        return w;
    }

    /*
        *   Date:2019/8/17
        *   Author:Ge Chen
        *   Description:my interface
    */
    public double[] getVectorByMatrix(double[][] matrix, double CR) {
        double[] res = {1.0};
        int n = matrix.length;
        if (n == 1)
            return res;
        double lamda = 0;
        double[] vector = new double[n];
        lamda = cigenValueVector(matrix, vector);
        if (!sigleConsistencyCheck(lamda, n, CR)) {
            UsingGASolveProblems usingGASolveProblems = new UsingGASolveProblems(
                    matrix, matrix.length, matrix[0].length,
                    matrix.length - 1, matrix.length - 1
            );
            List<double[][]> Matrixs = usingGASolveProblems.GAMain();
            double tCR = CR;
            double[][] newMatrix = Matrixs.get(0);
            for (double[][] tm : Matrixs) {
                double tlamda = cigenValueVector(tm, new double[tm.length]);
                double cr = (tlamda - tm.length) / (tm.length - 1) / calRI(tm.length);
                if (cr < tCR) {
                    tCR = cr;
                    newMatrix = tm;
                }
            }
            lamda = cigenValueVector(newMatrix, vector);
        }
        return vector;
    }

    /**
     * @return
     * @Description 递归计算叶子节点的绝对权重（最后一层目标层）
     * @Date 2019/4/1 18:49
     * @Param
     **/
    private void calAbVector(Node node, double weight, double[] resVector) {
        double[] tVector = new double[node.getVector().length];
        for (int i = 0; i < node.getVector().length; i++)
            tVector[i] = weight * node.getVector()[i];
        if (node.getChild() == null) {
            addVector(resVector, tVector);
            return;
        }
        for (int i = 0; i < node.getChild().size(); i++) {
            calAbVector(node.getChild().get(i), tVector[i], resVector);
        }
    }

    // 定义向量加法
    private void addVector(double[] a, double[] b) {
        // try catch
        for (int i = 0; i < a.length; i++)
            a[i] += b[i];
    }


    ///////////////////////// 新需求 //////////////////////////////

    /**
     * @return AHP树
     * @Author WH
     * @Description 构造AHP树，完成一致性检验，计算层次权重向量，一致性调整等
     * @Date 2019/4/4 10:39
     * @Param
     **/
    public Node constructAHP(Node ahpTree) {
        return constructAHP(ahpTree, 0.1);
    }

    public Node constructAHP(Node ahpTree, double CR) {
        // 计算各节点最大特征值及其特征向量、层次单排序一致性检验及调整
        preOrdor(ahpTree, CR);
        ArrayList<Double> arrayList = new ArrayList<Double>();
        calLastAbVector(ahpTree, 1, arrayList);
        ahpTree.setAbVector(arrayList);
        return ahpTree;
    }


    /**
     * @return
     * @Author WH
     * @Description 计算最后一层目标层的目标权重
     * @Date 2019/4/4 10:50
     * @Param
     **/
    private void calLastAbVector(Node node, double weight, ArrayList<Double> arrayList) {
        if (node.getChild() == null) {
            arrayList.add(weight);
            return;
        }
        double[] tVector = new double[node.getVector().length];
        for (int i = 0; i < node.getVector().length; i++)
            tVector[i] = weight * node.getVector()[i];
        for (int i = 0; i < node.getChild().size(); i++) {
//            System.out.println(i);
            calLastAbVector(node.getChild().get(i), tVector[i], arrayList);
        }
    }


    /**
     * @return
     * @Author WH
     * @Description 单方案打分主函数
     * @Date 2019/4/4 10:31
     * @Param 层次分析法树ahpTree、方案属性权重矩阵w
     **/
    public double AHPScore(Node ahpTree, double[] w) {
        double resScore = 0;
        ArrayList<Double> abVector = ahpTree.getAbVector();
        // try catch
        if (abVector.size() != w.length)
            return -1;
        for (int i = 0; i < w.length; i++)
            resScore += abVector.get(i) * w[i];
        return resScore;
    }

    ////////////////////////////////////////////////////////////////////////


    /**
     * @return 特征值、特征向量vector
     * @Author JiangJinghu
     * @Description 计算最大特征值及其特征向量
     * @Param [matrix, vector]
     **/
    private double cigenValueVector(double[][] matrix, double[] vector) {
        int n = matrix.length;
        double[][] mm = new double[n][n];
        for (int j = 0; j < n; j++) {
            double t = 0;
            for (int i = 0; i < n; i++) {
                t += matrix[i][j];
            }
            for (int i = 0; i < n; i++) {
                mm[i][j] = matrix[i][j] / t;
            }
        }

        double sum = 0;
        for (int i = 0; i < n; i++) {
            vector[i] = 0;
            for (int j = 0; j < n; j++) {
                vector[i] += mm[i][j];
            }
            sum += vector[i];
        }
        //归一化得到最大特征向量
        for (int i = 0; i < n; i++) {
            vector[i] = vector[i] / sum;
        }
        //计算特征值
        double lamda = 0;

        for (int i = 0; i < n; i++) {
            double t = 0;
            for (int j = 0; j < n; j++) {
                t += matrix[i][j] * vector[j];
            }
            lamda += t / vector[i];
        }
        lamda = lamda / n;
        return lamda;
    }


    /**
     * @return n对应的RI
     * @Author JiangJinghu
     * @Description 计算RI
     * @Param 矩阵的阶数n
     **/
    private double calRI(int n) {
        //double RI[]={0,0,0,0.58,0.9,1.12,1.24,1.32,1.41,1.45,1.49,1.51};
        //if(n<RI.length) return RI[n];
        if (n == 0 || n == 1) return 0;
        Random random = new Random(System.currentTimeMillis());
        double c[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 1.0 / 2, 1.0 / 3, 1.0 / 4, 1.0 / 5, 1.0 / 6, 1.0 / 7, 1.0 / 8, 1.0 / 9};
        int iter = 500;
        double[][] a = new double[n][n];
        double[] w = new double[n];
        double lam = 0;

        for (int it = 0; it < iter; it++) {
            for (int i = 0; i < n; i++) {
                for (int j = i + 1; j < n; j++) {
                    a[i][j] = c[random.nextInt(c.length)];
                    a[j][i] = 1 / a[i][j];
                    a[i][i] = 1;
                }
            }
            lam += cigenValueVector(a, w);
        }
        lam = lam / iter;
        return (lam - n) / (n - 1);
    }


    /**
     * @return void
     * @Author JiangJinghu
     * @Description 先序遍历并计算非叶子节点, 不满足一致性时进行调整：init()
     * @Param [ahpTree]
     **/
    private void preOrdor(Node ahpTree, double CR) {
        // 给出的树缺失矩阵和相对权重的向量
        // if(ahpTree.getMatrix() == null && ahpTree.getVector() == null && ahpTree.getChild() != null)
        // 如果给定相对权重
        if (ahpTree.getVector() != null) {
            // 归一化
            double sum = 0;
            double[] resVector = new double[ahpTree.getVector().length];
            for (int i = 0; i < ahpTree.getVector().length; i++)
                sum += ahpTree.getVector()[i];
            for (int i = 0; i < ahpTree.getVector().length; i++)
                resVector[i] = ahpTree.getVector()[i] / sum;
//            System.out.println(Arrays.toString(resVector));
            ahpTree.setVector(resVector);
        }
        // 如果未给定相对权重，只给定成对比较矩阵
        else {
            if (ahpTree.getMatrix() == null)
                return;
            double[][] matrix = ahpTree.getMatrix();
            int n = matrix.length;
            double lamda = 0;
            double[] vector = new double[n];

            lamda = cigenValueVector(matrix, vector);
            // 若不满足一致性，则进行调整
            if (!sigleConsistencyCheck(lamda, n, CR)) {
                System.out.print("不满足一致性检验：");
//            System.out.println("lamda"+lamda);
//            System.out.println("CR"+(lamda-n)/(n-1)/calRI(n));
//            System.out.println("RI"+calRI(n));
                System.out.println(Arrays.deepToString(matrix));
                // 一致性调整(遗传算法)
                UsingGASolveProblems usingGASolveProblems = new UsingGASolveProblems(
                        matrix, matrix.length, matrix[0].length,
                        matrix.length - 1, matrix.length - 1
                );
                List<double[][]> Matrixs = usingGASolveProblems.GAMain();
                // 选取CR最小的作更新
                double tCR = 0.1;
                double[][] newMatrix = Matrixs.get(0);
                for (double[][] tm : Matrixs) {
                    double tlamda = cigenValueVector(tm, new double[tm.length]);
                    double cr = (tlamda - tm.length) / (tm.length - 1) / calRI(tm.length);
                    if (cr < tCR) {
                        tCR = cr;
                        newMatrix = tm;
                    }
                }
                System.out.print("调整之后的矩阵为：");
//            System.out.println("CR"+tCR);
                System.out.println(Arrays.deepToString(newMatrix));
                lamda = cigenValueVector(newMatrix, vector);
            }
            ahpTree.setMaxLamda(lamda);
            ahpTree.setVector(vector);
            ahpTree.setCi((lamda - n) / (n - 1));
            ahpTree.setRi(calRI(n));
        }

        List<Node> child = ahpTree.getChild();
        if (child == null) {
            // 获得方案层方案数量
            NSolution = ahpTree.getVector().length;
            return;
        }
        for (Node c : child) {
            preOrdor(c, CR);
        }
    }


    // 层次单排序一致性检验
    private boolean sigleConsistencyCheck(double lamda, int n, double CR) {
//        System.out.println("CR: "+(lamda-n)/(n-1)/calRI(n));
        return (lamda - n) / (n - 1) / calRI(n) < CR;
    }

    // 层次总排序一致性检验
    private boolean generalConsistencyCheck(double[] CI, double[] a, double[] RI, double CR) {
        int n = CI.length;
        double ci = 0;
        double ri = 0;
        for (int i = 0; i < n; i++) {
            ci += a[i] * CI[i];
            ri += a[i] * RI[i];
        }
        return ci / ri < CR;
    }


    /**
     * @Author LiHongao
     * @Description 使用遗传算法进行一致性调整
     * @Param
     * @return
     **/
    public class UsingGASolveProblems {
        private MatrixCreater RawMatrixList;//初始矩阵群生成器
        private double[][] CandidateMatrix;//待一致性调整的候选矩阵
        private int CandidateMatrixRows;//候选矩阵的行数
        private int CandidateMatrixLines;//候选矩阵的列数
        private int M;//矩阵扰动的位置数
        private int N;//生成矩阵的个数
        private List<double[][]> AllTables;//存储所有扰动后的矩阵,作为出示父代群体
        private double[] W;//特征向量
        private double maxWValue = 0; //最大特征值
        private int generationNumber = 0; //迭代数

        public class Block {
            public double[][] Matrix;
            public double FValue;
            public int Index;
        }

        /// 构造函数
        // <param name="candidatematrix">候选矩阵</param>
        // <param name="r">候选矩阵的行数</param>
        // <param name="l">候选矩阵的列数</param>
        // <param name="n">生成矩阵的个数</param>
        // <param name="m">矩阵扰动的位置数</param>
        public UsingGASolveProblems(double[][] candidatematrix, int r, int l, int n, int m) {
            CandidateMatrixRows = r;
            CandidateMatrixLines = l;
            M = m;
            N = n;
            CandidateMatrix = new double[CandidateMatrixRows][CandidateMatrixLines];
            //MatrixCreater.CopyMatrix(candidatematrix, ref CandidateMatrix, CandidateMatrixRows, CandidateMatrixLines);
            CandidateMatrix = MatrixCreater.CopyMatrix(candidatematrix, CandidateMatrixRows, CandidateMatrixLines);
            RawMatrixList = new MatrixCreater(CandidateMatrix, r, l, n, m);
            AllTables = RawMatrixList.AllMatrix();
            W = new double[CandidateMatrixRows];
        }

        // 计算两个矩阵之间的相似度
        // <param name="Matrix1">矩阵1</param>
        // <param name="Matrix2">矩阵2</param>
        // <param name="rows">矩阵行数</param>
        // <param name="lines">矩阵列数</param>
        // <returns>两个矩阵的相似度</returns>
        private double DidtanceBetweenTwoMatrix(double[][] Matrix1, double[][] Matrix2, int rows, int lines) {
            double sum = 0;
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < lines; j++) {
                    sum += (Math.log(Matrix1[i][j]) - Math.log(Matrix2[i][j])) * (Math.log(Matrix1[i][j]) - Math.log(Matrix2[i][j]));
                }
            }
            return sum;
        }

        // 计算当前矩阵的CIF值
        // <param name="JudgeMatrix">判断矩阵</param>
        // <param name="W">权重向量</param>
        // <param name="n">矩阵的维数</param>
        // <returns>CIF值</returns>
        private double CIF(double[][] JudgeMatrix, double[] W, int n) {
            double Sum = 0;
            for (int i = 0; i < n; i++) {
                double sumtmp = 0;
                for (int k = 0; k < n; k++) {
                    sumtmp += (JudgeMatrix[i][k] * W[k]);
                }
                Sum += Math.abs(sumtmp - n * W[i]);
            }
            return Sum / n;
        }

        // 评价矩阵的适应度函数
        // <param name="Source">原判断矩阵</param>
        // <param name="JudgeMatrix">当前被评价的判断矩阵</param>
        // <returns>适应度值</returns>
        private double F(double[][] Source, double[][] JudgeMatrix) {
            MatrixLab judgeMatrixControl;//矩阵操作
            judgeMatrixControl = new MatrixLab(CandidateMatrixRows, 0.0001, JudgeMatrix);
            //judgeMatrixControl.returnResult2(ref W, ref maxWValue);
            W = judgeMatrixControl.returnResult1(W, maxWValue);
            maxWValue = judgeMatrixControl.returnResult2(W, maxWValue);
            //double CI = MatrixLab.CI(maxWValue, CandidateMatrixRows);
            //double CR = Math.Round(CI / MatrixLab.RI[CandidateMatrixRows - 1], 4);
            //return DidtanceBetweenTwoMatrix(Source, JudgeMatrix, CandidateMatrixRows, CandidateMatrixRows) + CIF(JudgeMatrix, W, CandidateMatrixRows);
            return CIF(JudgeMatrix, W, CandidateMatrixRows);// *CIF(JudgeMatrix, W, CandidateMatrixRows);
        }

        // 矩阵编码
        // <param name="Candidate">候选判断矩阵</param>
        // <param name="rows">矩阵的行数</param>
        // <returns>编码结果</returns>
        public double[] CodingMatrix(double[][] Candidate, int rows) {
            double[] code = new double[rows * rows];
            int index = 0;
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < rows; j++) {
                    code[index] = (9 * Candidate[i][j] - 1) / 80;
                    index++;
                }
            }
            return code;
        }

        // 矩阵解码
        // <param name="Candidate">解码向量</param>
        // <param name="n">矩阵的行数的平方</param>
        // <returns>判断矩阵</returns>
        public double[][] DecodingMatrix(double[] Candidate, int n) {
            int row = (int) Math.sqrt(n);
            int index = 0;
            double[][] Matrix = new double[row][row];
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < row; j++) {
                    Matrix[i][j] = (80 * Candidate[index] + 1) / 9;
                    index++;
                }
            }
            return Matrix;
        }

        // 判断是否找到最优解
        // <param name="esp">查找精度</param>
        // <returns>是否找到</returns>
        private List<double[][]> NearDegree(double esp) {
            List<double[][]> FianlMatrix = new ArrayList<double[][]>();
            MatrixLab judgeMatrixControl;//矩阵操作
            double CI;
            double CR;
            for (int i = 0; i < AllTables.size(); i++) {
                judgeMatrixControl = new MatrixLab(CandidateMatrixRows, 0.0001, AllTables.get(i));
                //judgeMatrixControl.returnResult2(ref W, ref maxWValue);
                W = judgeMatrixControl.returnResult1(W, maxWValue);
                maxWValue = judgeMatrixControl.returnResult2(W, maxWValue);
                CI = MatrixLab.CI(maxWValue, CandidateMatrixRows);
                CR = (CI * 1.0000) / MatrixLab.RI[CandidateMatrixRows - 1];
                if (CR < 0.1 && CR >= 0)
                    FianlMatrix.add(AllTables.get(i));
            }
            for (int j = 0; j < W.length; j++)
                if (W[j] < 0)
                    FianlMatrix.clear();
            return FianlMatrix;
        }

        // 返回有最小CR值得矩阵
        // <param name="Temp">矩阵族</param>
        // <returns>满足条件的block结构体</returns>
        private Block MiniMatrix(List<double[][]> Temp) {
            double[] We = new double[CandidateMatrixRows];
            double max = 0;
            if (Temp.size() > 0) {
                MatrixLab judgeMatrixControl;
                double CI;
                double CR;
                Block[] block = new Block[Temp.size()];
                for (int i = 0; i < Temp.size(); i++) {
                    judgeMatrixControl = new MatrixLab(CandidateMatrixRows, 0.0001, Temp.get(i));
                    //judgeMatrixControl.returnResult2(ref We, ref max);
                    We = judgeMatrixControl.returnResult1(We, max);
                    max = judgeMatrixControl.returnResult2(We, max);
                    CI = MatrixLab.CI(max, CandidateMatrixRows);
                    CR = (CI * 1.0000) / MatrixLab.RI[CandidateMatrixRows - 1];
                    block[i].Matrix = Temp.get(i);
                    block[i].FValue = CR;
                    block[i].Index = i;
                }
                block = SortTopN(block);
                return block[0];
            } else
                return new Block();
        }

        // 计算选择概率
        // <param name="i">第i个种群个体</param>
        // <returns>选择概率</returns>
        private double PS(int i, boolean flag) {
            int k = 0;
            double ps = 0;
            double sum = 0;
            for (k = 0; k < AllTables.size(); k++) {
                sum += F(CandidateMatrix, AllTables.get(k));
            }
            if (flag)
                ps = F(CandidateMatrix, AllTables.get(i)) / sum;
            else
                ps = 1 - (F(CandidateMatrix, AllTables.get(i)) / sum);
            return ps;
        }

        // 选择区间
        // <param name="i">第i个种群个体</param>
        // <returns>选择区间</returns>
        private double P(int i, boolean flag) {
            int k = 0;
            double p = 0;
            for (k = 0; k < i; k++) {
                p += PS(k, flag);
            }
            return p;
        }

        // 利用冒泡排序法对种群按照适应度升序排序
        // <param name="list">待排序种群</param>
        private Block[] SortTopN(Block[] list) {
            int i, j;
            Block temp = new Block();
            boolean done = false;
            j = 1;
            while ((j < list.length) && (!done)) {
                done = true;
                for (i = 0; i < list.length - j; i++) {
                    if (list[i].FValue > list[i + 1].FValue) {
                        done = false;
                        temp = list[i];
                        list[i] = list[i + 1];
                        list[i + 1] = temp;
                    }
                }
                j++;
            }
            return list;
        }

        // 选择前n个适应度最高的个体
        // </summary>
        // <param name="Source">待选择种群</param>
        // <param name="n">选择前n个</param>
        // <returns>选择结果</returns>
        private List<double[][]> ChooseTopN(List<double[][]> Source, int n) {
            List<double[][]> Res = new ArrayList<double[][]>();
            Res.clear();
            Block[] block = new Block[Source.size()];
            for (int i = 0; i < Source.size(); i++) {
                block[i] = new Block();
            }

            for (int i = 0; i < Source.size(); i++) {
                block[i].Matrix = Source.get(i);
                block[i].FValue = F(CandidateMatrix, Source.get(i));
                block[i].Index = i;
            }
            SortTopN(block);
            for (int j = 0; j < n; j++) {
                Res.add(block[j].Matrix);
            }
            return Res;
        }

        // 种群个体选择操作
        // <returns>第i个种群个体</returns>
        private int ChooseOpetator(int n, boolean flag) {
            Random Ran = new Random();
            double tmp = Ran.nextDouble();
            for (int i = 1; i <= n; i++) {
                if (tmp >= P(i - 1, flag) && tmp <= P(i, flag)) {
                    return i - 1;
                }
            }
            return -1;
        }

        // 种群个体的交叉操作
        // <param name="threshold">实行交叉操作的阈值</param>
        // <returns>交叉后的新个体</returns>
        private double[][] CrossOperator(double threshold, int n) {
            double[][] Father = AllTables.get(ChooseOpetator(n, true));
            double[][] Mother = AllTables.get(ChooseOpetator(n, true));
            double[] CodingFather = new double[CandidateMatrixRows * CandidateMatrixRows];
            double[] CodingMother = new double[CandidateMatrixRows * CandidateMatrixRows];
            double[] Child = new double[CandidateMatrixRows * CandidateMatrixRows];
            Random Ran = new Random();
            double u1;
            double u2;
            CodingFather = CodingMatrix(Father, CandidateMatrixRows);
            CodingMother = CodingMatrix(Mother, CandidateMatrixRows);
            for (int i = 0; i < CandidateMatrixRows * CandidateMatrixRows; i++) {
                u1 = Ran.nextDouble();
                u2 = Ran.nextDouble();
                double u3 = (Ran.nextDouble() - 0.5) * 4;
                if (u2 < 0.5) {
                    Child[i] = CodingFather[i] + u3 * (CodingMother[i] - CodingFather[i]);
                } else {
                    Child[i] = CodingMother[i] + u3 * (CodingFather[i] - CodingMother[i]);
                }
            }

            return DecodingMatrix(Child, CandidateMatrixRows * CandidateMatrixRows);
        }

        // 种群个体的变异操作
        // <param name="p">变异的位数</param>
        // <returns>变异后的新个体</returns>
        private double[][] ChangeMatrix(int p) {
            Random Ran = new Random();
            double Replace = 0;
            int index = 0;
            double[][] CandidateMember = AllTables.get(ChooseOpetator(N, false));
            double[] TmpRes = CodingMatrix(CandidateMember, CandidateMatrixRows);
            for (int i = 0; i < p; i++) {
                index = Ran.nextInt(CandidateMatrixRows * CandidateMatrixRows);
                Replace = Ran.nextDouble();
                TmpRes[index] = Replace;
            }
            double[][] tmpmatrix = DecodingMatrix(TmpRes, CandidateMatrixRows * CandidateMatrixRows);
            for (int j = 0; j < CandidateMatrixRows; j++) {
                tmpmatrix[j][j] = 1;
                for (int k = 0; k < CandidateMatrixRows; k++) {
                    if (j > k)
                        tmpmatrix[k][j] = 1 / tmpmatrix[j][k];
                }
            }
            return tmpmatrix;
        }

        // 遗传算法主程序
        //返回一个List表单
        // <returns>满足条件的矩阵族</returns>
        public List<double[][]> GAMain() {
            generationNumber = 0;
            int i = 0;
            double threshold = 0.01;
            int p = (int) CandidateMatrixRows * CandidateMatrixRows / 2;
            List<double[][]> listing;
            while ((listing = NearDegree(1)).size() <= 0) {
                List<double[][]> NewList = new ArrayList<double[][]>();
                NewList.clear();
                for (i = 0; i < N; i++) {
                    NewList.add(AllTables.get(ChooseOpetator(N, true)));
                    // if (i < (int)(N * 0.7))
                    NewList.add(CrossOperator(threshold, N));
                    //if (i < (int)(N * 0.1))
                    NewList.add(ChangeMatrix(p));
                }

                AllTables.clear();
                AllTables = ChooseTopN(NewList, N);

                generationNumber++;
            }
            return listing;
        }

        private String WeightString() {
            String str = "";
            for (int i = 0; i < W.length; i++)
                str += String.valueOf(W[i]) + ",";
            return String.format(" 权重向量:{%s}", str);
        }

        public String Final() {
            Block block = MiniMatrix(GAMain());
            return "一致性指标是:" + String.valueOf(block.FValue) + WeightString() + "遗传代数:" + String.valueOf(generationNumber);
        }
    }
}